home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / tcphdr.c < prev    next >
C/C++ Source or Header  |  1992-05-28  |  4KB  |  158 lines

  1. /* @(#) $Header: tcphdr.c,v 1.4 92/05/28 13:50:34 deyke Exp $ */
  2.  
  3. /* TCP header conversion routines
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "tcp.h"
  9. #include "ip.h"
  10. #include "internet.h"
  11.  
  12. /* Convert TCP header in host format into mbuf ready for transmission,
  13.  * link in data (if any). If ph != NULL, compute checksum, otherwise
  14.  * take checksum from tcph->checksum
  15.  */
  16. struct mbuf *
  17. htontcp(tcph,bp,ph)
  18. register struct tcp *tcph;
  19. struct mbuf *bp;
  20. struct pseudo_header *ph;
  21. {
  22.     int16 hdrlen;
  23.     register char *cp;
  24.  
  25.     hdrlen =  TCPLEN;
  26.     if(tcph->optlen > 0 && tcph->optlen <= TCP_MAXOPT){
  27.         hdrlen += tcph->optlen;
  28.     } else if(tcph->mss != 0){
  29.         hdrlen += MSS_LENGTH;
  30.     }
  31.     bp = pushdown(bp,hdrlen);
  32.     cp = bp->data;
  33.     cp = put16(cp,tcph->source);
  34.     cp = put16(cp,tcph->dest);
  35.     cp = put32(cp,tcph->seq);
  36.     cp = put32(cp,tcph->ack);
  37.     *cp++ = hdrlen << 2;    /* Offset field */
  38.     *cp = 0;
  39.     if(tcph->flags.congest)
  40.         *cp |= 64;
  41.     if(tcph->flags.urg)
  42.         *cp |= 32;
  43.     if(tcph->flags.ack)
  44.         *cp |= 16;
  45.     if(tcph->flags.psh)
  46.         *cp |= 8;
  47.     if(tcph->flags.rst)
  48.         *cp |= 4;
  49.     if(tcph->flags.syn)
  50.         *cp |= 2;
  51.     if(tcph->flags.fin)
  52.         *cp |= 1;
  53.     cp++;
  54.     cp = put16(cp,tcph->wnd);
  55.     if(ph == NULLHEADER){
  56.         /* Use user-supplied checksum */
  57.         cp = put16(cp,tcph->checksum);
  58.     } else {
  59.         /* Zero out checksum field for later recalculation */
  60.         *cp++ = 0;
  61.         *cp++ = 0;
  62.     }
  63.     cp = put16(cp,tcph->up);
  64.  
  65.     /* Write options, if any */
  66.     if(hdrlen > TCPLEN){
  67.         if(tcph->mss != 0){
  68.             *cp++ = MSS_KIND;
  69.             *cp++ = MSS_LENGTH;
  70.             cp = put16(cp,tcph->mss);
  71.         } else
  72.             memcpy(cp,tcph->options,tcph->optlen);
  73.     }
  74.     /* Recompute checksum, if requested */
  75.     if(ph != NULLHEADER)
  76.         put16(&bp->data[16],cksum(ph,bp,ph->length));
  77.  
  78.     return bp;
  79. }
  80. /* Pull TCP header off mbuf */
  81. int
  82. ntohtcp(tcph,bpp)
  83. register struct tcp *tcph;
  84. struct mbuf **bpp;
  85. {
  86.     int hdrlen,i,optlen,kind;
  87.     register int flags;
  88.     char hdrbuf[TCPLEN],*cp;
  89.  
  90.     i = pullup(bpp,hdrbuf,TCPLEN);
  91.     /* Note that the results will be garbage if the header is too short.
  92.      * We don't check for this because returned ICMP messages will be
  93.      * truncated, and we at least want to get the port numbers.
  94.      */
  95.     tcph->source = get16(&hdrbuf[0]);
  96.     tcph->dest = get16(&hdrbuf[2]);
  97.     tcph->seq = get32(&hdrbuf[4]);
  98.     tcph->ack = get32(&hdrbuf[8]);
  99.     hdrlen = (hdrbuf[12] & 0xf0) >> 2;
  100.     flags = hdrbuf[13];
  101.     tcph->flags.congest = flags & 64;
  102.     tcph->flags.urg = flags & 32;
  103.     tcph->flags.ack = flags & 16;
  104.     tcph->flags.psh = flags & 8;
  105.     tcph->flags.rst = flags & 4;
  106.     tcph->flags.syn = flags & 2;
  107.     tcph->flags.fin = flags & 1;
  108.     tcph->wnd = get16(&hdrbuf[14]);
  109.     tcph->checksum = get16(&hdrbuf[16]);
  110.     tcph->up = get16(&hdrbuf[18]);
  111.     tcph->mss = 0;
  112.     tcph->optlen = hdrlen - TCPLEN;
  113.  
  114.     /* Check for option field. Only space for one is allowed, but
  115.      * since there's only one TCP option (MSS) this isn't a problem
  116.      */
  117.     if(i < TCPLEN || hdrlen < TCPLEN)
  118.         return -1;      /* Header smaller than legal minimum */
  119.     if(tcph->optlen == 0)
  120.         return (int)hdrlen;     /* No options, all done */
  121.  
  122.     if(tcph->optlen > len_p(*bpp)){
  123.         /* Remainder too short for options length specified */
  124.         return -1;
  125.     }
  126.     pullup(bpp,tcph->options,tcph->optlen); /* "Can't fail" */
  127.     /* Process options */
  128.     for(cp=tcph->options,i=tcph->optlen; i > 0;){
  129.         kind = *cp++;
  130.         /* Process single-byte options */
  131.         switch(kind){
  132.         case EOL_KIND:
  133.             i--;
  134.             cp++;
  135.             return (int)hdrlen;     /* End of options list */
  136.         case NOOP_KIND:
  137.             i--;
  138.             cp++;
  139.             continue;       /* Go look for next option */
  140.         }
  141.         /* All other options have a length field */
  142.         optlen = uchar(*cp++);
  143.  
  144.         /* Process valid multi-byte options */
  145.         switch(kind){
  146.         case MSS_KIND:
  147.             if(optlen == MSS_LENGTH){
  148.                 tcph->mss = get16(cp);
  149.             }
  150.             break;
  151.         }
  152.         optlen = max(2,optlen); /* Enforce legal minimum */
  153.         i -= optlen;
  154.         cp += optlen - 2;
  155.     }
  156.     return (int)hdrlen;
  157. }
  158.